package code.easy.contentstate

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems

enum class ContentState {
    Loading, Content, Error, Empty
}

/**
 * 创建State
 * eg. var contentState by rememberEasyContentState()
 */
@Composable
fun rememberContentState(initContentState: ContentState = ContentState.Loading) =
    remember { mutableStateOf(initContentState) }

/**
 * 通过LazyPagingItems的状态创建State，方便配合Paging使用EasyContentState
 * @param isSwipeRefresh 是否是下拉刷新触发的refresh。如果是，则ContentState不会进入Loading状态
 *
 * @return contentState 初始值是ContentState.Content，会根据LazyPagingItems自动变更状态，如果初始值改成Loading，第一次Loading会闪一下
 */
@Composable
fun <T : Any> LazyPagingItems<T>.observerAsContentState(isSwipeRefresh: Boolean = false): ContentState {
    var contentState by remember { mutableStateOf(ContentState.Content) }
    LaunchedEffect(loadState.refresh, itemCount == 0) {
        when {
            loadState.refresh is LoadState.Error -> contentState = ContentState.Error
            loadState.refresh is LoadState.NotLoading -> contentState =
                if (loadState.append.endOfPaginationReached && itemCount == 0) ContentState.Empty
                else ContentState.Content
            loadState.refresh is LoadState.Loading && !isSwipeRefresh && itemCount == 0 -> contentState =
                ContentState.Loading
        }
    }
    return contentState
}

/**
 * ContentState 实现
 * @param contentState eg. var state by rememberEasyContentState()；当配合Paging使用时可调用 var state = lazyPagingItems.observerAsContentState()来创建state
 * @param enableScrollEmptyToRefresh 空页面是否可以滑动。当显示空视图时，是否允许滑动空页面以触发下拉刷新
 * @param enterAnim 切换状态时页面显示动画，默认逐渐显示 duration=300ms
 * @param exitAnim 切换状态时页面隐藏动画，默认瞬间隐藏 duration=0（就是没有动画，防止一个显示一个隐藏的过程中两种页面状态同时出现）
 *
 */
@Composable
fun EasyContentState(
    contentState: ContentState,
    modifier: Modifier = Modifier,
    loading: (@Composable BoxScope.() -> Unit),
    empty: (@Composable BoxScope.() -> Unit),
    error: (@Composable BoxScope.() -> Unit),
    enableScrollEmptyToRefresh: Boolean = true,
    enterAnim: EnterTransition = fadeIn(tween(300)),
    exitAnim: ExitTransition = fadeOut(tween(0)),
    content: @Composable BoxScope.() -> Unit
) {
    Box(modifier = modifier) {
        AnimatedVisibility(
            visible = contentState == ContentState.Content,
            enter = enterAnim,
            exit = exitAnim
        ) { content.invoke(this@Box) }
        AnimatedVisibility(
            visible = contentState == ContentState.Loading,
            enter = enterAnim,
            exit = exitAnim
        ) { loading.invoke(this@Box) }
        AnimatedVisibility(
            visible = contentState == ContentState.Empty,
            enter = enterAnim,
            exit = exitAnim,
            modifier = Modifier.apply { if (enableScrollEmptyToRefresh) verticalScroll(rememberScrollState()) }
        ) { empty.invoke(this@Box) }
        AnimatedVisibility(
            visible = contentState == ContentState.Error,
            enter = enterAnim,
            exit = exitAnim
        ) { error.invoke(this@Box) }
    }
}

